package com.sunyard.pcc.common.shiro;

import com.sunyard.pcc.common.bo.SysUserBO;
import com.sunyard.pcc.common.bo.SysUserCacheBO;
import com.sunyard.pcc.common.exception.PccCommonException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


/**
 * @Author: Hewei
 * @Description: shiro 工具类
 * @Date: Created in 17:11 2018/2/26
 */
@Slf4j
@Component
public class ShiroUtils {

    //是否使用redis
    public static Boolean useRedis;

    //是否将用户信息存入redis
    public static Boolean saveShiroInRedis;

    //加密算法
    public static final String HASH_ALGORITHM_NAME = "MD5";

    //循环次数
    public static final int HASH_INTERATIONS = 2;

    //登录页面url
    public static final String LOGIN_URL = "/sys/login";

    //登出URL
    public static final String LOGOUT_URL = "/sys/logout";

    @Value(value = "${sunyard.redis.open}")
    private Boolean pUseRedis;

    @Value(value = "${sunyard.shiro.redis}")
    private Boolean pSaveShiroInRedis;

    private static UserSaveService userSaveService;

    @Autowired
    @Qualifier(value = "sessionCache")
    private UserSaveService sessionUserSaveService;

    @Autowired
    @Qualifier(value = "redisCache")
    private UserSaveService redisUserSaveService;

    @PostConstruct
    private void init(){
        useRedis = pUseRedis;
        saveShiroInRedis = pSaveShiroInRedis;
        if (useRedis && saveShiroInRedis){
            userSaveService = redisUserSaveService;
        } else {
            userSaveService = sessionUserSaveService;
        }
    }


    private ShiroUtils(){

    }

    /**
     * 获取Session
     * @return
     */
    public static Session getSession(){
        Subject subject = getSubject();
        Session session = subject.getSession(false);
        if (session == null){
            session = subject.getSession();
        }
        if (session != null){
            return session;
        }
        return null;
    }

    /**
     * 获取shiro subject
     * @return
     */
    public static Subject getSubject(){
        return SecurityUtils.getSubject();
    }


    /**
     * 获取当前登录用户
     * @return
     */
    public static SysUserBO getUser() {
        return (SysUserBO) getSubject().getPrincipal();
    }


    /**
     * 获取用户完整信息
     * @return
     */
    public static SysUserCacheBO getCacheUser() throws PccCommonException {
        SysUserCacheBO sysUserCacheBO = userSaveService.getCacheUser();
        return sysUserCacheBO;
    }


    /**
     * 将用户存入Shiro Session
     * @param user
     * @throws PccCommonException
     */
    public static void setUserCacheIntoSession(SysUserCacheBO user) throws PccCommonException {
        userSaveService.saveUser(user);
    }


    /**
     * 根据salt对password进行MD5加密
     * @param password
     * @param salt
     * @return
     */
    public static String md5Encryption(String password, String salt){
        return new SimpleHash(HASH_ALGORITHM_NAME, password, ByteSource.Util.bytes(salt), HASH_INTERATIONS).toString();
    }


    /**
     * 用户登出
     */
    public static void logout() throws PccCommonException {
        Subject subject = SecurityUtils.getSubject();
        userSaveService.removeUser();
        subject.logout();
        log.info("用户退出成功");
    }


    /**
     * 拦截器中的通用url过滤
     * @param url
     * @return
     */
    public static boolean urlFilter(String url){
        if (LOGIN_URL.equals(url)
            || LOGOUT_URL.equals(url)
            || "/swagger-resources/configuration/ui".equals(url)
            || "/swagger-resources".equals(url)
            || "/swagger-resources/configuration/security".equals(url)){
            return true;
        }
        return false;
    }


}
